<?php

namespace common\models\db;

use adminApi\modules\rbac\models\Permissions;
use common\components\wtools\tools\ArrayHelper;
use common\components\wtools\tools\Model;
use Yii;
use yii\behaviors\BlameableBehavior;
use yii\behaviors\TimestampBehavior;

/**
 * This is the model class for table "{{%roles}}".
 *
 * @author
 * @property Permissions[] $permissions
 */
class Roles extends \common\models\db\tables\Roles
{
    const SCENARIO_TEST = 'test';


    public function behaviors()
    {
        $behaviors = parent::behaviors();
        $behaviors = ArrayHelper::merge($behaviors, [
            'timestamp' => [
                'class' => TimestampBehavior::class,
//                'createdAtAttribute' => false,
//                'updatedAtAttribute' => false,
            ],
            'blameable' => [
                'class' => BlameableBehavior::class,
                'createdByAttribute' => false,
                'updatedByAttribute' => false,
            ],
        ]);
        return $behaviors;
    }

    public function attributeLabels()
    {
        $attributeLabels = parent::attributeLabels();
        $attributeLabels = ArrayHelper::merge($attributeLabels, []);
        return $attributeLabels;
    }

    public function rules()
    {
        $rules = parent::rules();
        foreach ($rules as $k => $v) {
            if ($v[1] == 'required'){
                $rules[$k][0] = array_diff($rules[$k][0], ['created_at', 'updated_at', 'created_by', 'updated_by']);
            }
        }
        $rules = ArrayHelper::merge($rules, [
//            [[], 'required', 'on' => self::SCENARIO_TEST],
        ]);
        return $rules;
    }

    public function scenarios()
    {
        $scenarios = parent::scenarios();
        $scenarios = ArrayHelper::merge($scenarios, [
            self::SCENARIO_TEST => [],
        ]);
        return $scenarios;
    }


    /**
     * @return false|mixed|Roles[]
     */
    public static function getAllWithCache()
    {
        return Yii::$app->cache->getOrSet("db-Roles-getAllWithCache", function () {
            return static::find()->all();
        }, null);
    }

    /**
     * @param $id
     * @return false|Roles|mixed
     */
    public static function getByIdWithCache($id)
    {
        return Yii::$app->cache->getOrSet("db-Roles-getByIdWithCache/{$id}", function () use ($id) {
            return static::findOne($id);
        }, null);
    }

    public function deleteCaches()
    {
        Yii::$app->cache->delete("db-Roles-getAllWithCache");
        Yii::$app->cache->delete("db-Roles-getByIdWithCache/{$this->id}");
    }

    public function afterSave($insert, $changedAttributes)
    {
        parent::afterSave($insert, $changedAttributes);
        $this->deleteCaches();
    }

    public function afterRefresh()
    {
        parent::afterRefresh();
        $this->deleteCaches();
    }

    public function afterDelete()
    {
        parent::afterDelete();
        $this->deleteCaches();
    }

    /**
     * 同步角色的管理员
     * @param $adminerIds
     * @return void
     * @throws \Exception
     */
    public function syncAdminers($adminerIds)
    {
        $hasAdminerIds = [];
        $roleHasAdminers = RoleHasModels::find()
            ->andWhere(['role_id' => $this->id])
            ->andWhere(['model_type' => RoleHasModels::MODEL_TYPE_ADMINERS])
            ->all();
        foreach ($roleHasAdminers as $k => $v) {
            $hasAdminerIds[] = $v->model_id;
        }
        $toAddIds = array_diff($adminerIds, $hasAdminerIds);
        $toRmIds = array_diff($hasAdminerIds, $adminerIds);
        RoleHasModels::deleteAll(['role_id' => $this->id, 'model_type' => RoleHasModels::MODEL_TYPE_ADMINERS, 'model_id' => $toRmIds]);
        foreach ($toAddIds as $k => $v) {
            $roleHasAdminer = new RoleHasModels();
            $roleHasAdminer->role_id = $this->id;
            $roleHasAdminer->model_type = RoleHasModels::MODEL_TYPE_ADMINERS;
            $roleHasAdminer->model_id = $v;
            if (!$roleHasAdminer->save()) {
                throw new \Exception(Model::getModelError($roleHasAdminer));
            }
        }
    }

    /**
     * 同步角色的权限
     * @param $permissions
     * @return void
     * @throws \Exception
     */
    public function syncPermissions($permissions)
    {
        $hasAll = [];
        $hasAllPermissions = Permissions::find()
            ->all();
        foreach ($hasAllPermissions as $k => $v) {
            $hasAll[] = $v->path;
        }
        $toRemove = array_diff($hasAll, $permissions['all']);
        foreach ($toRemove as $k => $v) {
            $permission = Permissions::findOne(['path' => $v]);
            if ($permission) {
                $permission->delete();
            }
        }
        $toAdd = array_diff($permissions['all'], $hasAll);
        foreach ($toAdd as $k => $v) {
            $permission = new Permissions();
            $permission->path = $v;
            if (!$permission->save()) {
                throw new \Exception(Model::getModelError($permission));
            }
        }

        $roleHasAll = []; // 当前角色获取所有权限
        $roleHasPermissions = RoleHasModels::find()
            ->andWhere(['role_id' => $this->id])
            ->andWhere(['model_type' => RoleHasModels::MODEL_TYPE_PERMISSIONS])
            ->all();
        foreach ($roleHasPermissions as $k => $v) {
            $permission = Permissions::findOne($v->model_id);
            if ($permission) {
                $roleHasAll[] = $permission->path;
            }
        }
        $roleToRm = array_diff($roleHasAll, $permissions['has']); // 当前角色需要删除的权限
        foreach ($roleToRm as $k => $v) {
            $permission = Permissions::findOne(['path' => $v]);
            if ($permission) {
                RoleHasModels::deleteAll(['role_id' => $this->id, 'model_type' => RoleHasModels::MODEL_TYPE_PERMISSIONS, 'model_id' => $permission->id]);
            }
        }
        $roleToAdd = array_diff($permissions['has'], $roleHasAll);
        foreach ($roleToAdd as $k => $v) {
            $permission = Permissions::findOne(['path' => $v]);
            if ($permission) {
                $roleHasPermission = new RoleHasModels();
                $roleHasPermission->role_id = $this->id;
                $roleHasPermission->model_type = RoleHasModels::MODEL_TYPE_PERMISSIONS;
                $roleHasPermission->model_id = $permission->id;
                if (!$roleHasPermission->save()) {
                    throw new \Exception(Model::getModelError($roleHasPermission));
                }
            }
        }
    }

    # relations

    /**
     * @return \yii\db\ActiveQuery
     * @throws \yii\base\InvalidConfigException
     */
    public function getPermissions()
    {
        return $this->hasMany(Permissions::className(), ['id' => 'model_id'])
            ->viaTable(RoleHasModels::tableName(), ['role_id' => 'id'], function ($q) {
                $q->andWhere(['model_type' => RoleHasModels::MODEL_TYPE_PERMISSIONS]);
            });
    }

    # static funs

    public function test()
    {
        $test = self::instance();
        $test->setScenario(self::SCENARIO_TEST);
        $test->save();
        var_dump($test->toArray());
    }

    # funs
}
